# -*- coding: utf-8 -*-


from sympy import sympify, Eq

from mathsolver.functions.base.base import BaseValue, new_latex


def safe_sympify(obj):
    if isinstance(obj, BaseGeo):
        return obj.sympify()
    else:
        return sympify(obj, locals=locals)


class GeoExpr(BaseValue):
    deduced = False
    label = ""
    operate = ""

    def __init__(self, value, *objs):
        super(GeoExpr, self).__init__(value)
        if not objs:
            self.value = value
            self.objs = value

        else:
            self.value = value
            self.objs = objs

    def __hash__(self):
        return 33

    def sympify(self):
        return self.objs

    def deduce(self, known):
        self.deduced = True
        return []

    def printing(self):
        return new_latex(self.sympify())


class BaseGeoEq(GeoExpr):
    operate = "="

    def deduce(self, known):
        if isinstance(self.objs[0], BaseLine) and isinstance(self.objs[1], BaseLine):
            match = [obj for obj in known if
                     isinstance(obj, BaseCollinear) and obj.intersect(self.objs[0]) and obj.intersect(self.objs[1])]
            if len(match) == 2:
                lines = []
                points = [m.objs[0] for m in match]
                for line in self.objs:
                    temp = set(line.name).union(points).difference(set(line.name).intersection(points))
                    lines.append(BaseLine("".join(temp)))

                self.deduced = True
                deduction = BaseGeoEq(None, *lines)
                deduction.label = "利用共线性质"
                yield deduction

    def __eq__(self, other):
        if isinstance(other, BaseGeoEq):
            return len(set(other.objs).intersection(self.objs)) == len(self.objs)
        else:
            return False

    def sympify(self):
        for obj1, obj2 in zip(self.objs[:-1], self.objs[1:]):
            yield Eq(safe_sympify(obj1), safe_sympify(obj2))

    def printing(self):
        return self.operate.join(
            [obj.printing() if isinstance(obj, BaseGeo) else new_latex(sympify(obj, locals=locals)) for obj in
             self.objs])


class BaseTriEq(GeoExpr):
    def __init__(self, value, *objs):
        super(BaseTriEq, self).__init__(value, *objs)
        self.value = value
        if not objs:
            self.objs = [BaseTriangle(value[i]) for i in range(0, len(value), 2)]
        else:
            self.objs = objs

    def deduce(self, known):
        self.deduced = True
        for angles in zip(*[tri.getAllAngle() for tri in self.objs]):
            output = BaseGeoEq(None, *angles)
            output.label = "全等三角形对角相等"
            yield output

        for lines in zip(*[tri.getAllLine() for tri in self.objs]):
            output = BaseGeoEq(None, *lines)
            output.label = "全等三角形对边相等"
            yield output

    def sympify(self):
        return []

    def printing(self):
        return "≌".join([obj.printing() for obj in self.objs])


class BaseCollinear(GeoExpr):
    def intersect(self, line):
        name1 = line.name
        name2 = self.objs[1].name
        return len(set(name1).intersection(name2)) > 0

    def sympify(self):
        return []


class GeoPoly(GeoExpr):
    def __init__(self, sympy_str, string, value, *objs):
        super(GeoPoly, self).__init__(value, *objs)
        self.objs = objs
        self.sympy_str = sympy_str
        self.string = string

    def sympify(self):
        yield self.sympy_str

    def printing(self):
        return self.string


class BaseGeo(BaseValue):
    deduced = False

    def __hash__(self):
        return 42

    def sympify(self):
        return sympify("%s(%s)" % (str(self.__class__.__name__), self.name))

    def deduce(self):
        self.deduced = True
        return []

    def printing(self):
        return self.name


class BaseLine(BaseGeo):
    def __init__(self, name):
        super(BaseLine, self).__init__(name)
        self.name = tuple(name)
        self.value = name

    def __eq__(self, obj):
        if isinstance(obj, BaseLine):
            obj_name = obj.name
        elif isinstance(obj, str):
            obj_name = obj
        else:
            return False

        if len(set(self.name).intersection(obj_name)) == 2:
            return True

        return False

    def printing(self):
        return "".join(self.name)


class BaseTriangle(BaseGeo):
    def __init__(self, name):
        super(BaseTriangle, self).__init__(name)
        self.name = name
        self.value = name

    def printing(self):
        return "\\triangle %s" % "".join(self.name)
